package com.gmono.managers.generic;

import com.gmono.managers.Common;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * 通用对象 封装对象相关的一切操作
 */
public abstract class GenericObject implements  IObject {

    protected String tablename;

    @Override
    public String getTableName() {
        return tablename;
    }

    protected final ArrayList<String> columns=new ArrayList<>();
    protected final HashMap<String,Object> pairs=new HashMap<>();
    protected final HashMap<String,Class> types=new HashMap<>();
    //映射表 将类型映射为一个输入列名返回
    protected final HashMap<Class,Method> setfunmap =new HashMap<>();
    protected final HashMap<Class,Method> getfunmap=new HashMap<>();
    protected boolean AddMethod(Class res_type,String name)
    {
        try {
            String setname=String.format("set%s",name);
            String getname=String.format("get%s",name);
            Method m=ResultSet.class.getMethod(getname,String.class);
            getfunmap.put(res_type,m);
            //set方法用于设置语句中的参数
            m=PreparedStatement.class.getMethod(setname,String.class);
            setfunmap.put(res_type,m);
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }
    public GenericObject()
    {
        //目前只有两个类型支持
        AddMethod(int.class,"Int");
        AddMethod(String.class,"String");
    }
    protected boolean hasKey(String key)
    {
        return columns.contains(key);
    }

    /**
     * 用于校验value的类型
     * @param key 键
     * @param value 值
     * @return 是否正确
     */
    protected boolean validateType(String key,Object value)
    {
        Class c=types.get(key);
        return value.getClass()==c;
    }

    @Override
    public <T> T getValue(String key) {
        if(!pairs.containsKey(key)) return null;
        //此处不检查
        return (T)pairs.get(key);
    }

    /**
     * 设置列的value
     * 如果columns中没有此key则返回失败
     * @param key   键
     * @param value 值
     * @return 是否成功
     */
    @Override
    public boolean setColumnValue(String key, Object value) {
        if(!columns.contains(key))
        {
            return false;
        }
        //类型校验
        if(!validateType(key,value)) return false;
        //修改
        pairs.put(key,value);
        return true;
    }

    /**
     * 通过一行来填充对象
     *
     * @param row 数据库返回的行
     * @return 对象
     */
    @Override
    public IObject fillObject(ResultSet row) {
        //填充
        for(String key:columns)
        {
            Class cls=types.get(key);
            Method m= getfunmap.get(cls);
            try {
                //获取值并填充
                Object obj=m.invoke(row,key);
                pairs.put(key,obj);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
        return this;
    }

    /**
     * 返回对象的值列表
     *
     * @return 值列表
     */
    @Override
    public Map<String, Object> getValues() {
        return pairs;
    }

    /**
     * 根据给定选取匹配的补全信息 如果失败返回null
     **/
    @Override
    public IObject getInfo() {
        //根据已有的value填充where语句
        Connection c= Common.c;
        String sql="SELECT * FROM %s WHERE %s";
        String wheresql =pairs.entrySet().stream()
                .map(e-> String.format("%s=%s",e.getKey(),"?"))
                .reduce((x,y)-> String.format("%s and %s", x,y)).get();
        String osql= String.format(sql, getTableName(),wheresql);
        try {
            PreparedStatement s=c.prepareStatement(osql);
            //替换对应参数
            int now=1;
            for(Map.Entry<String,Object> entry:pairs.entrySet())
            {
                Method m=setfunmap.get(entry.getKey());
                //调用相应的设置方法设置参数
                m.invoke(s,now,entry.getValue());
                now++;
            }

            //查询
            ResultSet set=s.executeQuery();
            if(!set.next()) return null;
            //获取
            return fillObject(set);
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return null;
        } catch (InvocationTargetException e) {
            e.printStackTrace();
            return null;
        }


    }

    /**
     * 各键的类型
     *
     * @return
     */
    @Override
    public Map<String, Class> getTypes() {
        return types;
    }

    /**
     * 列名表
     *
     * @return 列名列表
     */
    @Override
    public Collection<String> getColumns() {
        return columns;
    }


}
